<!-- 验证码渲染组件 -->

<template>
    <canvas id="canvas" ref="canvas" :width="canvasWidth" :height="canvasHeight" @click="generateVerifyCode"></canvas>
</template>

<script lang="ts">
export interface Props {
    canvasWidth: number;
    canvasHeight: number;
}
</script>

<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';

/* -- PROPS -- */

const props = withDefaults(defineProps<Props>(), {
    canvasWidth: 120,
    canvasHeight: 45,
});

/* -- EVENTS -- */

const emit = defineEmits<{
    generateVerifyCode: [verifyCodeStr: string];
}>();

/* -- [BLOCK Name] -- */

/* - PROPERTIES - */

let canvas: HTMLCanvasElement = null!;
let context: CanvasRenderingContext2D = null!;

/* - LIFE CYCLE - */

onMounted(() => {
    canvas = document.getElementById('canvas') as HTMLCanvasElement;
    context = canvas.getContext('2d') as CanvasRenderingContext2D;

    canvas.width = props.canvasWidth;
    canvas.height = props.canvasHeight;

    generateVerifyCode();
});

onUnmounted(() => {
    // TODO
});

/* - METHODS - */

// 生成验证码
function generateVerifyCode() {
    const str = randomString(4);
    const verifyCodeStr = str.toLowerCase();

    draw(str);

    emit('generateVerifyCode', verifyCodeStr);
}

// 随机颜色 rgb
function randomColor(): string {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

// 随机字符串
function randomString(length = 32): string {
    const str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    const maxLength = str.length;

    let res = '';

    for (let i = 0; i < length; i++) {
        const index = Math.floor(Math.random() * maxLength);
        res += str.charAt(index);
    }

    return res;
}

// 绘制文本和干扰图形
function draw(str: string) {
    context.clearRect(0, 0, canvas.width, canvas.height);

    drawStr(str);

    drawNoiseLine(5);

    drawNoisePoint(30);
}

// 绘制文本
function drawStr(str: string) {
    for (let i = 0; i < str.length; i++) {
        const char = str.charAt(i);
        const deg = (Math.random() * 30 * Math.PI) / 180; // 产生0~30之间的随机弧度
        const x = 15 + i * 20;
        const y = 25 + Math.random() * 7;

        context.font = 'bold 30px 微软雅黑';
        context.translate(x, y);
        context.rotate(deg);

        context.fillStyle = randomColor();
        context.fillText(char, 0, 0);

        context.rotate(-deg);
        context.translate(-x, -y);
    }
}

// 绘制干扰线条
function drawNoiseLine(count = 5) {
    const width = canvas.width;
    const height = canvas.height;

    for (let i = 0; i <= count; i++) {
        const [x1, y1] = [Math.random() * width, Math.random() * height];
        const [x2, y2] = [Math.random() * width, Math.random() * height];

        context.strokeStyle = randomColor();
        context.beginPath();
        context.moveTo(x1, y1);
        context.lineTo(x2, y2);
        context.stroke();
    }
}

// 绘制干扰点
function drawNoisePoint(count = 30) {
    const width = canvas.width;
    const height = canvas.height;

    for (let i = 0; i <= count; i++) {
        const x = Math.random() * width;
        const y = Math.random() * height;

        context.strokeStyle = randomColor();
        context.beginPath();
        context.moveTo(x, y);
        context.lineTo(x + 1, y + 1);
        context.stroke();
    }
}
</script>

<style scoped>
#canvas {
    cursor: pointer;
    border: 1px solid #e9ecf7;
}
</style>
